﻿Imports BlogML.Xml
Imports DotNetNuke.Modules.Blog.Business
Imports System.Linq
Imports System.Xml
Imports System.IO
Imports DotNetNuke.Modules.Blog.Settings
Imports DotNetNuke.Services.Localization
Public Class BlogReader
#Region "Private Fields"

  Protected _blogID As Integer
  Protected _blogMLFilePath As String
  Protected _importUnapprovedComments As Boolean
  Protected _importUnapprovedTrackback As Boolean
  Protected _portalID As Integer
  Protected _tabID As Integer
  Protected _categoryMapping As New CategoryMapCollection
  Protected _blogController As New BlogController
  Protected _entryController As New EntryController

#End Region

  Public Event LogMessage(ByVal sender As Object, ByVal e As LogMessageEventArgs)

#Region "Public Properties"

  Public ReadOnly Property XmlData As String
    Get
      Dim contents As String = String.Empty
      Using reader As New StreamReader(BlogMLFilePath)
        contents = reader.ReadToEnd()
      End Using

      Return contents
    End Get
  End Property

  Public Property BlogMLFilePath As String
    Get
      Return _blogMLFilePath
    End Get
    Set(ByVal Value As String)
      _blogMLFilePath = Value
    End Set
  End Property

  Public ReadOnly Property XmlReader As XmlTextReader
    Get
      Dim byteArray As Byte() = Encoding.UTF8.GetBytes(XmlData)
      Dim stm As New MemoryStream(byteArray)
      Return New XmlTextReader(stm)
    End Get
  End Property

  Public Property PortalID As Integer
    Get
      Return _portalID
    End Get
    Set(ByVal Value As Integer)
      _portalID = Value
    End Set
  End Property

  Public Property TabID As Integer
    Get
      Return _tabID
    End Get
    Set(ByVal Value As Integer)
      _tabID = Value
    End Set
  End Property

  Public Property BlogID As Integer
    Get
      Return _blogID
    End Get
    Set(ByVal Value As Integer)
      _blogID = Value
    End Set
  End Property

  Public Property ImportUnapprovedComments As Boolean
    Get
      Return _importUnapprovedComments
    End Get
    Set(ByVal Value As Boolean)
      _importUnapprovedComments = Value
    End Set
  End Property

  Public Property ImportUnapprovedTrackback As Boolean
    Get
      Return _importUnapprovedTrackback
    End Get
    Set(ByVal Value As Boolean)
      _importUnapprovedTrackback = Value
    End Set
  End Property

#End Region

  Protected Function ValidateProperties() As Boolean
    Return True
  End Function

  Public Overridable Function Import() As Boolean

    ValidateProperties()

    'Initialize BlogML
    Dim blog As BlogMLBlog

    Try
      blog = BlogMLSerializer.Deserialize(XmlReader)
    Catch ex As Exception
      'Handle failure to import xml

    End Try

    Dim BlogModuleSettings As BlogSettings = BlogSettings.GetBlogSettings(PortalID, TabID)
    _categoryMapping.UseChildBlogs = BlogModuleSettings.AllowChildBlogs

    If blog IsNot Nothing Then
      If blog.Categories.Count > 0 Then
        LoadCategories(blog.Categories, BlogID)
      End If
      If blog.Posts.Count > 0 Then
        'LoadTags()
        LoadPosts(blog.Posts, BlogID)
      End If
    End If
    Utility.CreateAllEntryLinks(PortalID, BlogID)

  End Function

  Protected Overridable Sub LoadPosts(ByVal MLPosts As BlogMLBlog.PostCollection, ByVal RootBlogID As Integer)
    For Each objPostML As BlogMLPost In MLPosts
      Dim newBlogEntry As EntryInfo = GetNewBlogEntry(objPostML)

      If _categoryMapping.UseChildBlogs AndAlso objPostML.Categories.Count > 0 Then
        newBlogEntry.BlogID = _categoryMapping.GetCategoryMapByCategoryRef(objPostML.Categories(0).Ref).ChildBlogID
      Else
        newBlogEntry.BlogID = RootBlogID
      End If

      newBlogEntry.Published = objPostML.Approved
      newBlogEntry.AddedDate = objPostML.DateCreated
      newBlogEntry.EntryID = _entryController.AddEntry(newBlogEntry)

      AssociateCategories(objPostML, newBlogEntry)

      OnLogMessage(New LogMessageEventArgs(GetFormattedMessage("CreatedPost", newBlogEntry.Title), LogMessageType.OkMessage))

      If objPostML.Comments.Count > 0 Then
        ImportComments(newBlogEntry.EntryID, objPostML.Comments)
      End If

      If objPostML.Trackbacks.Count > 0 Then
        ImportTrackbacks(newBlogEntry.EntryID, objPostML.Trackbacks)
      End If
    Next

  End Sub

  Protected Overridable Function GetNewBlogEntry(ByVal objPostML As BlogMLPost) As EntryInfo
    Return New EntryInfo() With { _
              .Title = objPostML.Title, _
              .Description = objPostML.Excerpt.Text, _
              .Entry = objPostML.Content.Text}
  End Function

  Protected Sub AssociateCategories(ByVal objPostML As BlogMLPost, ByVal newBlogEntry As EntryInfo)
    For Each categoryReference As BlogMLCategoryReference In objPostML.Categories
      Dim catmap As CategoryMap = _categoryMapping.GetCategoryMapByCategoryRef(categoryReference.Ref)
      If catmap IsNot Nothing Then
        CategoryController.UpdateCategoriesByEntry(newBlogEntry.EntryID, catmap.CategoryID)
      End If
    Next
  End Sub

  Protected Sub ImportComments(ByVal EntryID As Integer, ByVal MLComments As BlogMLPost.CommentCollection)
    Dim myCommentController As New CommentController
    For Each comment As BlogMLComment In MLComments
      If comment.Approved Or ImportUnapprovedComments Then
        Dim newComment As New CommentInfo() With { _
            .EntryID = EntryID, _
            .Title = comment.Title, _
            .AddedDate = comment.DateCreated, _
            .Approved = comment.Approved, _
            .Author = comment.UserName, _
            .Comment = comment.Content.Text, _
            .Email = comment.UserEMail, _
            .UserFullName = comment.UserName, _
            .Website = comment.UserUrl}

        myCommentController.AddComment(newComment)
        OnLogMessage(New LogMessageEventArgs(GetFormattedMessage("CreatedComment", comment.Title), LogMessageType.OkMessage))

        'LogEvent(Localization.GetString("CreatedComment", Me.LocalResourceFile) & ": " & comment.Title, MessageType.OkMessage)
      Else
        OnLogMessage(New LogMessageEventArgs(GetFormattedMessage("UnapprovedComment", comment.Title), LogMessageType.ErrorMessage))

        'LogEvent(Localization.GetString("UnapprovedComment", Me.LocalResourceFile) & ": " & comment.Title, MessageType.ErrorMessage)
      End If
    Next
  End Sub

  Protected Sub ImportTrackbacks(ByVal EntryID As Integer, ByVal TrackbacksML As BlogMLPost.TrackbackCollection)
    Dim myCommentController As New CommentController
    For Each objTrackbackML As BlogMLTrackback In TrackbacksML
      If objTrackbackML.Approved Or ImportUnapprovedTrackback Then
        Dim newComment As New CommentInfo() With { _
            .EntryID = EntryID, _
            .AddedDate = objTrackbackML.DateCreated, _
            .Approved = objTrackbackML.Approved, _
            .Author = "Trackback", _
            .Title = objTrackbackML.Title, _
            .Website = objTrackbackML.Url, _
            .Comment = String.Format("Trackback <a href=""{0}"">{0}</a>.", objTrackbackML.Url)}
        myCommentController.AddComment(newComment)

        OnLogMessage(New LogMessageEventArgs(GetFormattedMessage("CreatedTrackback", objTrackbackML.Title), LogMessageType.OkMessage))

        ' LogEvent(Localization.GetString("CreatedTrackback", Me.LocalResourceFile) & ": " & objTrackbackML.Title, MessageType.OkMessage)
      Else
        OnLogMessage(New LogMessageEventArgs(GetFormattedMessage("UnapprovedTrackback", objTrackbackML.Title), LogMessageType.ErrorMessage))

        'LogEvent(Localization.GetString("UnapprovedTrackback", Me.LocalResourceFile) & ": " & objTrackbackML.Title, MessageType.ErrorMessage)
      End If
    Next
  End Sub

  Protected Sub LoadCategories(ByVal MLCategories As BlogMLBlog.CategoryCollection, ByVal BlogID As Integer)
    _categoryMapping.Items.Clear()
    Dim RootBlog As BlogInfo = _blogController.GetBlog(BlogID)

    If _categoryMapping.UseChildBlogs Then
      CreateChildBlogs(RootBlog, MLCategories)
    Else
      CreateCategories(MLCategories)
    End If

  End Sub

  'Protected Sub LoadTags()
  '  _tagCollection.Clear()

  '  Dim doc As New XmlDocument()

  '  doc.Load(Me.XmlReader)

  '  Dim nsmgr As XmlNamespaceManager = New XmlNamespaceManager(doc.NameTable)
  '  nsmgr.AddNamespace("bml", "http://www.blogml.com/2006/09/BlogML")


  '  Dim posts As XmlNodeList = doc.GetElementsByTagName("post")

  '  For Each post As XmlNode In posts
  '    Dim tags As New ArrayList

  '    If post.ChildNodes.Count <= 0 Then
  '      Continue For
  '    End If

  '    Dim postid As String = post.Attributes("id").Value

  '    Dim tagNodes As XmlNodeList = post.SelectNodes("descendant::bml:tags/bml:tag", nsmgr)
  '    For Each tagNode As XmlNode In tagNodes
  '      If tagNode.Attributes IsNot Nothing Then
  '        tags.Add(tagNode.Attributes("ref").Value)
  '      End If
  '    Next

  '    If tags.Count > 0 Then
  '      _tagCollection.Add(postid, String.Join(",", tags.ToArray("".GetType())))
  '    End If
  '  Next
  'End Sub

  Protected Sub CreateCategories(ByVal MLCategories As BlogMLBlog.CategoryCollection)
    Dim mlcats As List(Of ExtendedMLCategory) = (From cat In MLCategories _
                                                      Order By cat.ParentRef, cat.Title _
                                                      Select New ExtendedMLCategory(cat)).ToList()

    mlcats.PopulatePaths()

    Dim categoryList As List(Of CategoryInfo) = CategoryController.ListCategoriesSorted(PortalID)

    For Each categoryML As ExtendedMLCategory In mlcats

      Dim newCategoryMap As New CategoryMap() With {.CategoryRef = categoryML.ID}
      'Search for existing category 
      Dim currentCategory As CategoryInfo = GetCategoryIfItExists(categoryList, categoryML)
      If currentCategory Is Nothing Then
        'create new category 
        Dim ParentCategoryMap As CategoryMap = _categoryMapping.GetCategoryMapByCategoryRef(categoryML.ParentRef)

        CategoryController.AddCategory(categoryML.Title, ParentCategoryMap.CategoryID, PortalID)

        'This is only needed because of a shortcoming in the AddCategory method.  
        'There is no way to find out the categoryID of the recently added category
        categoryList = CategoryController.ListCategoriesSorted(PortalID)
        currentCategory = GetCategoryIfItExists(categoryList, categoryML)
        If currentCategory IsNot Nothing Then
          newCategoryMap.CategoryID = currentCategory.CatId
          OnLogMessage(New LogMessageEventArgs(GetFormattedMessage("CreatedCategory", currentCategory.Category), LogMessageType.OkMessage))
        Else
          'error
        End If

      Else 'use existing category 
        newCategoryMap.CategoryID = currentCategory.CatId
        OnLogMessage(New LogMessageEventArgs(GetFormattedMessage("FoundCategory", currentCategory.Category), LogMessageType.OkMessage))
      End If

      _categoryMapping.Items.Add(newCategoryMap)

    Next

  End Sub

  Protected Function GetCategoryIfItExists(ByRef categoryList As List(Of CategoryInfo), ByVal categoryML As ExtendedMLCategory) As CategoryInfo
    Return (From cat In categoryList Where cat.FullCat = categoryML.Path Select cat).FirstOrDefault()
  End Function

  Protected Sub CreateChildBlogs(ByVal rootBlog As BlogInfo, ByVal MLCategories As BlogMLBlog.CategoryCollection)
    For Each objCategoryML As BlogMLCategory In MLCategories
      Dim newCategoryMap As New CategoryMap() With {.CategoryRef = objCategoryML.ID}

      If GetChildBlogIdByTitle(objCategoryML.Title, rootBlog.BlogID) <> -1 Then 'Child blog already present.
        newCategoryMap.ChildBlogID = GetChildBlogIdByTitle(objCategoryML.Title, rootBlog.BlogID)
        OnLogMessage(New LogMessageEventArgs(GetFormattedMessage("FoundCategory", objCategoryML.Title), LogMessageType.InfoMessage))

        'LogEvent(String.Format("{0}: {1}", Localization.GetString("FoundCategory", Me.LocalResourceFile), objCategoryML.Title), MessageType.InfoMessage)

      Else 'Add new child blog.
        Dim newChildBlog As New BlogInfo() With { _
            .Title = objCategoryML.Title, _
            .Description = objCategoryML.Description, _
            .ParentBlogID = rootBlog.BlogID, _
            .Public = True, _
            .UserID = rootBlog.UserID, _
            .AllowAnonymous = rootBlog.AllowAnonymous, _
            .MustApproveAnonymous = rootBlog.MustApproveAnonymous, _
            .AllowComments = rootBlog.AllowAnonymous, _
            .MustApproveComments = rootBlog.MustApproveComments, _
            .AllowTrackbacks = rootBlog.AllowTrackbacks, _
            .MustApproveTrackbacks = rootBlog.MustApproveTrackbacks, _
            .ShowFullName = rootBlog.ShowFullName}
        newCategoryMap.ChildBlogID = _blogController.AddBlog(newChildBlog)

        OnLogMessage(New LogMessageEventArgs(GetFormattedMessage("CreatedCategory", objCategoryML.Title), LogMessageType.OkMessage))

        'LogEvent(String.Format("{0}: {1}", Localization.GetString("CreatedCategory", Me.LocalResourceFile), objCategoryML.Title), MessageType.OkMessage)
      End If
      _categoryMapping.Items.Add(newCategoryMap)
    Next
  End Sub

  Protected Function GetChildBlogIdByTitle(ByVal Title As String, ByVal ParentBlogID As Integer) As Integer
    Dim ChildBlogs As ArrayList = _blogController.ListBlogs(PortalID, ParentBlogID, True)
    For Each ChildBlog As BlogInfo In ChildBlogs
      If ChildBlog.Title = Title Then
        Return ChildBlog.BlogID
      End If
    Next
    Return -1
  End Function

  Protected Overridable Sub OnLogMessage(ByVal e As LogMessageEventArgs)
    RaiseEvent LogMessage(Me, e)
  End Sub

  Protected Shared Function GetFormattedMessage(ByVal key As String, ByVal ParamArray args() As Object) As String
    Return String.Format(Localization.GetString(key, "/desktopmodules/DnnBlogML/App_LocalResources/Shared.resx"), args)
  End Function

End Class
